package ace.cmp.security.oauth2.resource.server.autoconfig.config;

import ace.cmp.json.api.JsonService;
import ace.cmp.security.autoconfig.SecurityBootstrapAutoConfigure;
import ace.cmp.security.oauth2.resource.server.core.introspection.UserInfoOpaqueTokenIntrospector;
import ace.cmp.security.oauth2.resource.server.core.properties.Oauth2ResourceServerSecurityProperties;
import ace.cmp.security.oauth2.resource.server.core.service.Oauth2SecurityService;
import ace.cmp.security.oauth2.resource.server.core.service.impl.Oauth2ResourceServerSecurityServiceLoginSupplier;
import ace.cmp.security.oauth2.resource.server.core.service.impl.Oauth2ResourceServerSpringSecurityService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.server.resource.authentication.OpaqueTokenAuthenticationProvider;
import org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector;
import org.springframework.security.oauth2.server.resource.introspection.SpringOpaqueTokenIntrospector;

/**
 * @author caspar
 * @date 2023/2/6 20:09 自动配置oauth2 resource server
 */
@Slf4j
@EnableConfigurationProperties({
    OAuth2ResourceServerProperties.class,
    Oauth2ResourceServerSecurityProperties.class
})
@AutoConfigureBefore({SecurityBootstrapAutoConfigure.class})
@AllArgsConstructor
@Configuration
public class Oauth2ResourceServerSecurityServiceAutoConfigure {

  @Bean
  @ConditionalOnMissingBean
  public OpaqueTokenIntrospector opaqueTokenIntrospector(
      OAuth2ResourceServerProperties resourceServerProperties,
      JsonService jsonService
  ) {
    OpaqueTokenIntrospector tokenIntrospector =
        new SpringOpaqueTokenIntrospector(
            resourceServerProperties.getOpaquetoken().getIntrospectionUri(),
            resourceServerProperties.getOpaquetoken().getClientId(),
            resourceServerProperties.getOpaquetoken().getClientSecret());
    UserInfoOpaqueTokenIntrospector userInfoOpaqueTokenIntrospector = new UserInfoOpaqueTokenIntrospector(tokenIntrospector, jsonService);
    return userInfoOpaqueTokenIntrospector;
  }

  @Bean
  @ConditionalOnMissingBean
  public Oauth2ResourceServerSecurityServiceLoginSupplier oauth2ResourceServerSecurityServiceLoginSupplier(
      HttpServletRequest request,
      HttpServletResponse response,
      OpaqueTokenIntrospector opaqueTokenIntrospector
  ) {
    OpaqueTokenAuthenticationProvider provider = new OpaqueTokenAuthenticationProvider(opaqueTokenIntrospector);
    Oauth2ResourceServerSecurityServiceLoginSupplier supplier = new Oauth2ResourceServerSecurityServiceLoginSupplier(request, response, provider);
    return supplier;
  }

  @Bean("securityService")
  @ConditionalOnMissingBean
  public Oauth2SecurityService securityService(Oauth2ResourceServerSecurityServiceLoginSupplier oauth2ResourceServerSecurityServiceLoginSupplier) {
    Oauth2SecurityService securityService = new Oauth2ResourceServerSpringSecurityService(oauth2ResourceServerSecurityServiceLoginSupplier);
    return securityService;
  }
}
